/** Author: JTrapp@Google.com
* (c) 07.01.2008 */

/**
* Access to the map
* @type GMap2
*/
var map;

/**
* Access to the Geocoder
* @type GClientGeocoder
*/
var geocoder;

/**
* The icon
* @type GIcon
*/
var myIcon;

/** Cache indices 
* @type Object
*/
var indices = new Object();

/** Has the data from the table already been loaded?
* @type=boolean
*/
var loaded =false;

var geocodingErrors = 0;

/** init store finder*/
function SF_init() {
    if (!loaded) {
        resetMap();
        readCSV(inputURL);
    }
}

/** Init map and load the table*/
function resetMap(){
    if (adminMode){ // clear textarea
        textarea.value = "";
    }
    clearLog();

    map = new google.maps.Map2(_gel("SF_map"));
    geocoder = new google.maps.ClientGeocoder();
    map.setCenter(new google.maps.LatLng(41.875696,-87.624207), 3); 
    createIcon(iconURL);
    initMapControls();
    loaded = true;
}

/** Read fcsv data in csv form.*/
function read(text){
    var lines = text.split("\n");
    var startIdx=0;
    while (!lines[startIdx].match(/^STORE_CODE/i)){
        if (adminMode){ // add header lines to textarea
            textarea.value += lines[startIdx]+"\n";
        }
        startIdx++;
    }

    if (startIdx<lines.length){
        var reallabels = lines[startIdx++].split(DELIMITER);
        var labels = new Array();
        for (var i=0; i< reallabels.length; i++){
            labels[i]= reallabels[i].replace(/^\s+|\s+$/,"").toLowerCase(); //trim...
        }
        if (getIndex(labels, latitudeLabel)==-1){ // Add latitude for output table
            log ("No Geocode data in "+lines[startIdx-1]);
            labels[labels.length]=latitudeLabel.toLowerCase();
            reallabels[reallabels.length]=latitudeLabel;
        }
        if (getIndex(labels, longitudeLabel)==-1){ // Add longitude for output table
            labels[labels.length]=longitudeLabel.toLowerCase();
            reallabels[reallabels.length]=longitudeLabel;
        }
        if (getIndex(labels, accuracyLabel)==-1){ // Add accuracy for qs
            labels[labels.length]=accuracyLabel.toLowerCase();
            reallabels[reallabels.length]=accuracyLabel;
        }
        if (adminMode){
            printHeader(reallabels);
        }
        
        var numShops = lines.length-startIdx;
        var bounds = new google.maps.LatLngBounds( );    
        for (var i = startIdx; i<lines.length; i++) {
            var line = lines[i].replace(/\s+$/,""); //trim trailing spaces/newlines
             var c = line.split(DELIMITER);
            createMarkerCSV(labels, c, bounds, i, printMarker);
        }    
        //google.maps.Log.writeHtml( "<a href=\""+inputURL+"\">"+numShops+ " addresses loaded.</a>");     
    } else if (adminMode) {
        log( "<a href=\""+inputURL+"\">Illegal format in shoplist. </a> Can't find header in "+ lines.length+" lines "+startIdx+".");
    }
    log ("Done. To store the geocoded data, copy the listings from the Basic Settings tab and save it to file.");
    if (geocodingErrors>0){
        log ("There have been "+geocodingErrors+". These may have happened due"+
            "to limitations of geocode requests that can be performed. If you"+
            "click on 'Load Map..' in the bsic settings, this will rerun the"+
            "geocoder on the remaining places.");
    }
}

/** Read fcsv data in csv form.*/
function readCSV(requestURL){
    _IG_FetchContent(requestURL, function (responseText) {read(responseText);});
}

/** Add map controls*/
function initMapControls() {
    map.addControl(new google.maps.SmallMapControl());
    map.setMapType(G_HYBRID_MAP);
    if (prefs.getBool("showMapTypeControls")) { 
        map.addControl(new google.maps.MapTypeControl());
    }
    //
    //    if (prefs.getBool("showSearchControls")){
    //        // create a local search control and add it to your map
    //        google.load("uds", "1");
    //
    //        var lsc = new google.maps.LocalSearch(); 
    //        map.addControl(new google.maps.LocalSearch());
    //    }
    
}

/**
* Create a marker on the map for the given address. 
*/
function createMarkerCSV(labels, values, bounds, rowNr, callback) {
    var longitude = values[getIndex(labels, longitudeLabel)];
    if ((longitude == undefined)||(longitude == "undefined")||(longitude.replace(/^\s+|\s+$/,"") == "")) {  // With Geocoding request
         createMarkerGeocode(labels, values, bounds, rowNr, callback, 0);
    } else { //without geocoding request
         createMarker(labels, values, bounds, rowNr, callback);
    }
}

function formatMessage(format, labels, values){
    var message = format; // Create new Ob ject
    for (var i=0; i<labels.length;i++){
        var regex1 = new RegExp("[{]"+labels[i]+"[}]","gi");
        message = message.replace(regex1, values[i]);
        var regex2 = new RegExp("[{]"+i+"[}]","g");
        message = message.replace(regex2, values[i]);
    }
    return message;
}

function loadData(url) { 
    _IG_FetchContent(url, function(response) {
       textarea.value=response;
    });
}



function createMarkerGeocode(labels, values, bounds, rowNr, callback, count) { 
        var address = formatMessage(addressFormat, labels, values);
    geocoder.getLocations(address, function(response) {
        values[getIndex(labels, latitudeLabel)]=""; //mark latitude
        values[getIndex(labels, longitudeLabel)]=""; //mark longitude
        values[getIndex(labels, accuracyLabel)]=""; //mark longitude
        if (!response ) {
            log("<p>Failed geocoding request for line "+rowNr+".");
            callback(rowNr, values);
       } else if (response.Status.code == 620 || response.Status.code == 500) { // too many request, retry later
            if (count<3){
                window.setTimeout( function(){
                        createMarkerGeocode(labels, values, bounds, rowNr, callback, count+1);
                    }, 5000);
            } else {
                log("Failed geocoding "+address +" with status "+response.Status.code+" on line "+rowNr+" after "+count+" retries.");
                geocodingErrors++;
                callback(rowNr, values);
            }
        } else if (response.Status.code == 602) {
                log("Failed geocoding "+address +": Bad address (status "+response.Status.code+") on line "+rowNr+".");

                callback(rowNr, values);
        } else if (response.Status.code != 200) {
                log("Failed geocoding "+address +" with status "+response.Status.code+" on line "+rowNr+".");
                callback(rowNr, values);
                geocodingErrors++;
            } else { // success
            values[getIndex(labels, latitudeLabel)] = response.Placemark[0].Point.coordinates[1];
            values[getIndex(labels, longitudeLabel)] = response.Placemark[0].Point.coordinates[0];
            values[getIndex(labels, accuracyLabel)] = response.Placemark[0].AddressDetails.Accuracy;
            createMarker(labels, values, bounds, rowNr, callback);   
            //_gel("geoStatus").value+=("<p>Geocoding "+address + " : "+response.Placemark[0].Point.coordinates[1]+","+response.Placemark[0].Point.coordinates[0]+"."+"</p>\n");
        }
    });
}

/** Create a marker with an info window*/
function createMarker(labels, values, bounds, rowNr, callback) {
    var point = new google.maps.LatLng(
        values[getIndex(labels, latitudeLabel)], values[getIndex(labels, longitudeLabel)]);
    var marker = new google.maps.Marker(point, {icon:myIcon});
    GEvent.addListener(marker, "click", function() {
        marker.openInfoWindowHtml(formatMessage(infoFormat, labels, values),{maxWidth : 120});
    });
    map.addOverlay(marker);
    callback(rowNr, values);
    bounds.extend(point);
    var zoomlevel = map.getBoundsZoomLevel(bounds);
    zoomlevel=(zoomlevel>15)?15:zoomlevel;
    zoomlevel=(zoomlevel<7)?7:zoomlevel;
    map.setCenter(bounds.getCenter(), zoomlevel);
    //log("Bounds: ("+bounds.getSouthWest().lat()+","+bounds.getSouthWest().lng()+") ("+bounds.getNorthEast().lat()+""+bounds.getNorthEast().lng()+") "+zoomlevel);           
}

/** Print a line of values. Only called in admin mode.*/
function printMarker(rowNr, values){
    if (adminMode){
        textarea.value += values[0];
        for (var i=1; i<values.length; i++){
            var value = values[i]==undefined?"":values[i];
            textarea.value += DELIMITER+value;
        }
        textarea.value += "\n";
    }
}

/** Print the table header. Only called in admin mode.*/
function printHeader(labels){
    textarea.value += labels[0];
    for (var i=1; i<labels.length; i++){
        textarea.value += DELIMITER+labels[i];
    }
    textarea.value += "\n";
}

/** 
* Get the index for a certain keyword in an array of strings.
* Index will be cached, if the value has been found. If the value
* has not been found, '-1' is returned, wich is not stored. 
*/
function getIndex(labels, key) {
    var lckey = key.toLowerCase(); 
    var index = indices[key];
    if (index!=null){
        return index;
    }
    for (var i =0, string; string = labels[i]; i++) {
        if (string == lckey) {
            indices[lckey]=i; // Remember this for the next time.
            return i;
        }
    }
    return -1; //do not store this result in dices, because the key may be added to header later
}

/** Create the icon*/
function createIcon(iconURL){
    if (iconURL==null||iconURL.length==0){
            myIcon=G_DEFAULT_ICON;
    } else if (iconURL!=null) {
        myIcon = new google.maps.Icon();
        myIcon.iconSize = new google.maps.Size(prefs.getMsg("iconWidth"), prefs.getMsg("iconHeight"));
        myIcon.iconAnchor = new google.maps.Point(prefs.getMsg("iconAnchorX"), prefs.getMsg("iconAnchorY"));
        myIcon.infoWindowAnchor = new google.maps.Point(prefs.getMsg("iconWindowX"),prefs.getMsg("iconWindowY"));
        myIcon.infoWindowAnchor = myIcon.iconAnchor;
        myIcon.image = _IG_GetImageUrl(iconURL);
    } 
}


function log(message) {
    _gel("geoStatus").value+=message+"\n";
    _gel("geoStatus").style.display="block";
}

function clearLog(){
    _gel("geoStatus").value="";
    _gel("geoStatus").style.display="none";
}
